/**
本文件参考：https://blog.csdn.net/weixin_44080304/article/details/125065724
*/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <pthread.h>
#include "lib/bmi088.h"

int fd, fdLED, fdBut;
FILE *fp;
char abcd123;
char filePATH[30];
int csvLine;

int valButPC2 = 1 << 8;
int fileNums;
char flagAlarm = 1;
unsigned char buf[3];
unsigned char gbuf[7];
short gx, gy, gz;
const char LED_ON = 1, LED_OFF = 0;

/**
 * @brief   bmi088 读取数据函数
 * @param   addr: 寄存器地址
 * @return  buf[1]: 读取到的数据
 */
unsigned char bmi_read(unsigned char addr){
    buf[0] = (addr | 0x80);
    read(fd, buf, 2);

    return buf[1];
}

/**
 * @brief   bmi088 读取数据函数
 * @param   addr: 寄存器地址
 * @return  buf[1]: 读取到的数据
 */
void bmi_write(unsigned char addr, unsigned char val){
    buf[0] = (addr & 0x7f);
    buf[1] = val;
    write(fd, buf, 2);
}

/**
 * @brief   bmi088 初始化函数
 * @param   outtime: 超时时间，单位 s
 * @return  返回值小于零则超时
 */
void bmi_init(int outtime){
    unsigned long long i = 0;// ms
    
    // get id
    while((bmi_read(0x00) != BMI_G_ID) && i < (outtime*1000)){
        usleep(5000);
        i += 5;
    }

    // rang +-2000
    while((bmi_read(BMI_G_RANG) != Plus_Minus_2000) && i < (outtime*1000)){
        bmi_write(BMI_G_RANG, Plus_Minus_2000);
        usleep(5000);
        i += 5;
    }

    bmi_write(BMI_G_BANDWIDTH, ODR_2000_FD_532);

    // 
    while((bmi_read(0x11) != 0x00) && i < (outtime*1000)){
        bmi_write(0x11, 0x00);
        usleep(5000);
        i += 5;
    }

    // interrupt
    while((bmi_read(0x15) != 0x80) && i < (outtime*1000)){
        bmi_write(0x15, 0x80);
        usleep(5000);
        i += 5;
    }

    // outPP
    while((bmi_read(0x16) != 0x00) && i < (outtime*1000)){
        bmi_write(0x16, 0x00);
        usleep(5000);
        i += 5;
    }

    // data ready interrupt to INT1 and INT2
    while((bmi_read(0x18) != 0x81) && i < (outtime*1000)){
        bmi_write(0x18, 0x81);
        usleep(5000);
        i += 5;
    }

    if(i >= (outtime*1000)){
        outtime = -1;
    }
}

void collectOver(void){// 数据收集接收后的处理函数
    write(fdLED, &LED_OFF, 1);

    for(; csvLine < 128; csvLine ++){
        fprintf(fp, "0,0,0\n");
    }

    fclose(fp);

    // 每次采集完输出文件名
    printf("\nfile \"%s\" create OK!\n", filePATH);
    fileNums ++;
}

void *buttonThread(void *arg){
    int	flags;

    fdBut = open("/dev/Button_PC2", O_RDWR | O_NONBLOCK);

    flags = fcntl(fdBut, F_GETFL);
	fcntl(fdBut, F_SETFL, flags & ~O_NONBLOCK);

	while (1){
		// if (read(fdBut, &valButPC2, 4) == 4)
		// 	printf("get button: 0x%x\n", valButPC2);
		// else
		// 	printf("while get button: -1\n");

        read(fdBut, &valButPC2, 4);
        if(valButPC2 == 0){
            sprintf(filePATH, "./HarData/%c/%c-%03d.csv", abcd123, abcd123, fileNums);
            fp = fopen (filePATH, "w");
            csvLine = 0;
            flagAlarm = 0;
            write(fdLED, &LED_ON, 1);
            alarm(2);// set alarm
        }else {
            alarm(0);// cancel alarm
            if(!flagAlarm){
                flagAlarm = 1;
                collectOver();
            }
        }
	}
}

void myTimer(int sig){
    if(SIGALRM == sig){
        flagAlarm = 1;
        collectOver();
    }
    return ;
}

int main(int argc, char **argv){
    int outTime = 5;// s
    int i;
    pthread_t tid;

    if(argc > 3 || argc < 2){
        printf("\nUseage:\n");
        printf("%s <(data-file-name)/ginit> [num]\n", argv[0]);
        printf("data-file-name: 需要收集的某一字符的数据文件的名称\n");
        printf("    例如输入 a, 每次采集完数据将会生成一个 a-num.txt (num = 0, 1, 2, ... ...) 保存此次数据\n");
        printf("ginit: init bmi088\n");
        printf("    每次上电后需要初始化一次 bmi088\n");
        printf("num: num 起始值");
        printf("    若不输入此参数，则 num 从 0 开始，如果已经有相应文件，那么它将被覆盖！\n");
        return -1;
    }
    fd = open("/dev/bmi088", O_RDWR);
    if (fd < 0)
	{
		printf(" can not open /dev/bmi088!\n");
        printf("打开设备文件 /dev/bmi088 失败!\n");
		return -1;
	}
    fdLED = open("/dev/V851s_LED", O_RDWR);
    if (fdLED < 0)
    {
        printf("open device V851s_LED error\n");
        return -1;
    }

    pthread_create(&tid, NULL, buttonThread, NULL);
    if (fdBut < 0)
	{
		printf(" can not open /dev/Button_PC2!\n");
        printf("打开设备文件 /dev/Button_PC2 失败!\n");
		return -1;
	}
    // bmi_init(outTime);
    // if(outTime < 0){
    //     printf("BMI088 init out time!\n");
    //     return -1;
    // }

    signal(SIGALRM, myTimer);

    /* 本程序不会自动初始化 bmi088，请上电后初始化(ginit)一次 bmi088 */
    if(strcmp(argv[1], "ginit") == 0){
        write(fdLED, &LED_ON, 1);
        bmi_write(BMI_SOFTINIT, 0x00);
        printf("BMI088 Soft Reset CMD Send OK!\n");
        sleep(1);
        outTime = 5;
        bmi_init(outTime);
        if(outTime < 0){// 初始化超时，重试一次或自行检查硬件
            printf("BMI088 Init Out Time!Plese Retry\n");
            return -1;
        }
        printf("BMI088 Init OK!\n");
        write(fdLED, &LED_OFF, 1);
    }else {
        if(argc == 3){
            sscanf(argv[2], "%d", &fileNums);
            if(fileNums < 0){
                return -1;
            }
        }
        abcd123 = argv[1][0];
        while(1){
            if(valButPC2 == 0 && !flagAlarm){
                gbuf[0] = 0x82;
                read(fd, gbuf, 7);
                gx = gbuf[1] + (gbuf[2]<<8);
                gy = gbuf[3] + (gbuf[4]<<8);
                gz = gbuf[5] + (gbuf[6]<<8);
                // printf("gx:%d gy:%d gz:%d\n", gx, gy, gz);
                fprintf(fp, "%d,%d,%d\n", gx, gy, gz);
                csvLine ++;
            }
            // 把采样频率从 40Hz 变更为 64Hz，看别人的数据都是特意 128 个一组，估计是为了方便 FFT ？
            usleep(15625);
        }
    }

    close(fd);
    close(fdLED);
    close(fdBut);

    return 0;
}
